<?php
declare (strict_types = 1);

namespace app\controller\backend;

use app\exception\ModelException;
use app\model\Attachment;
use app\model\Category;
use app\model\Route;
use app\model\Website;
use app\service\ApiService;
use app\service\CategoryService;
use app\validate\CategoryValidate;
use Overtrue\Pinyin\Pinyin;
use think\exception\ValidateException;
use think\facade\Cache;
use think\facade\Db;

class CategoryController extends BaseController
{

    protected $cacheKeyArr = 'hc_module_cate_arr';
    /**
     * 显示资源列表
     *
     * @return \think\response\Json
     * @throws \app\exception\ModelException
     * @throws \app\exception\ModelEmptyException
     */
    public function index(Category $category): \think\response\Json
    {
        $websiteId = (int)input('param.website_id');
        if(!$websiteId){
            return jsonReturn(-1,'网站ID不能为空');
        }
        $lang = input('lang');
        $where = [
            'seller_id' => $this->admin['seller_id'],
            'website_id' => $websiteId,
        ];
        if(empty($lang)){
            $lang = 'zh';
        }
        $Website = new Website();
        $website = $Website -> getWebsite (['id'=>$websiteId,'seller_id'=>$this->admin['seller_id']])['data'];
        $domain = $website['domain'];
        if($lang != 'zh'){
            $domain = $domain .'/'.$lang;
        }
        $where['lang'] = $lang;
        $with = [
            'thumbnail' => function($query){
                $query->field('id,name,url');
            },'banner' => function($query){
                $query->field('id,name,url');
            }
        ];
        $cateCacheKey = 'hc_cate_' . $this->admin['seller_id'] . '_' . $websiteId .'_' . $lang;
        $categoryList = Cache::get($cateCacheKey);
        if(empty($categoryList)){
            $categoryList = $category->with($with)->where($where)->select()->each(function (&$item)use($domain){
                if(!preg_match('/-$/',$item['path'])){
                    $item['path'] = $item['path'] . '-';
                    $item -> save();
                }
                if($item['type'] == 1 || $item['type'] == 4){
                    if(!empty($item['alias'])){
                        if($item['alias'] == '/'){
                            $item['fullUrl'] = 'http://' . $domain;
                        }else{
                            $item['fullUrl'] = 'http://' . $domain . $item['alias'].'.'.config('route.url_html_suffix');
                        }
                    }else{
                        $item['fullUrl'] = 'http://' . $domain . '/list/index/'.$item['id'].'.'.config('route.url_html_suffix');
                    }
                }else if($item['type'] == 3){
                    $item['fullUrl'] = $item['alias'];
                }else{
                    $item['fullUrl'] = 'javascript:;';
                }
            });
            $categoryList = $categoryList->toArray();
            $categoryList = makeTree($categoryList);
            Cache::set($cateCacheKey,$categoryList);
        }
        return jsonReturn(0,'success',$categoryList);
    }

    /**
     * 保存新建的资源
     *
     * @return \think\response\Json
     * @throws \app\exception\ModelException
     * @throws \app\exception\ModelEmptyException
     */
    public function save(CategoryService $categoryService,Category $Category): \think\response\Json
    {
        if(request()->isPost()){
            $param = input('post.');
            // 数据验证
            try{
                if(!empty($param['parent_map'])){
                    $param = $this->getMapCateData($param);
                }
                validate(CategoryValidate::class)->scene('save')->check($param);
            }catch(ValidateException $e){
                return jsonReturn(-1, $e->getError());
            }
            $param['seller_id'] = $this->admin['seller_id'];
            $category = $Category->existCategory(['title'=>$param['title'],'seller_id'=>$param['seller_id'],'website_id'=>$param['website_id'],'lang'=>$param['lang'],'parent_id'=>$param['parent_id']])['data'];
            if(!empty($category)){
                return jsonReturn(-2,'栏目已经存在');
            }
            if(in_array($param['type'],[1,4]) && empty($param['alias'])){
                if($param['list_tpl'] == 'index'){
                    $param['alias'] = '/';
                }else{
                    $pinyin = new Pinyin();
                    $cacheKey = $param['seller_id'] .'_'.$param['website_id'] .'_'. $param['lang'] . '_website_cache_key';
                    $settingData = Cache::get($cacheKey);
                    if(empty($settingData)){
                        $settingData = ApiService::setWebsiteSetting($param['seller_id'],$param['website_id'],$param['lang']);
                    }

                    if(!empty($settingData['alias_rule']) && $settingData['alias_rule'] == 1){
                        $param['alias'] = strtolower('/' . $pinyin -> abbr($param['title']));
                    }else{
                        $param['alias'] = strtolower('/' . $pinyin -> permalink($param['title'],''));
                    }
                }
            }
            if(!empty($param['alias']) && $param['alias'] != 'javascript:;'){
                $category = $Category->existCategory(['title'=>$param['alias'],'seller_id'=>$param['seller_id'],'website_id'=>$param['website_id'],'lang'=>$param['lang']])['data'];
            }
            if(!empty($category)){
                return jsonReturn(-3,'栏目别名已经存在');
            }
            $this->deleteCateCacheKey($param['website_id'],$param['lang']);
            return $categoryService -> createCategory($param);
        }
        return jsonReturn(-3,'请求方法错误');
    }

    /**
     * 显示指定的资源
     *
     * @return \think\response\Json
     * @throws \app\exception\ModelException
     * @throws \app\exception\ModelEmptyException
     */
    public function read(Category $category,Attachment $attachment): \think\response\Json
    {
        $param = input('param.');
        try {
            validate(CategoryValidate::class)->scene('read')->check($param);
        } catch (ValidateException $e) {
            return jsonReturn(-1, $e->getError());
        }
        $param['seller_id']= $this->admin['seller_id'];
        $with = [
            'thumbnail' => function($query){
                $query->field('id,name,url');
            },'banner' => function($query){
                $query->field('id,name,url');
            }
        ];
        $res = $category->getCategory($param,$with);

        return json($res);
    }

    /**
     * 保存更新的资源
     * @return \think\response\Json
     * @throws \app\exception\ModelException
     * @throws \app\exception\ModelEmptyException
     */
    public function update(CategoryService $categoryService,Category $Category): \think\response\Json
    {
        if(request()->isPost()){
            $param = input('post.');
            try {
                if(!empty($param['parent_map'])){
                    $param = $this->getMapCateData($param);
                }
                validate(CategoryValidate::class)->scene('update')->check($param);
            } catch (ValidateException $e) {
                return jsonReturn(-1, $e->getError());
            }
            $param['seller_id'] = $this->admin['seller_id'];
            $category = $Category->existCategory(['title'=>$param['title'],'seller_id'=>$param['seller_id'],'website_id'=>$param['website_id'],'lang'=>$param['lang'],'parent_id'=>$param['parent_id']])['data'];
            if(!empty($category) && $category['id'] != $param['id']){
                return jsonReturn(-2,'栏目已经存在');
            }
            $category = $Category->existCategory(['title'=>$param['alias'],'seller_id'=>$param['seller_id'],'website_id'=>$param['website_id']])['data'];
            if(!empty($category) && $category['id'] != $param['id']){
                return jsonReturn(-3,'栏目别名已经存在');
            }
            $this->deleteCateCacheKey($param['website_id'],$param['lang']);
            return $categoryService -> updateCategory($param);
        }
        return jsonReturn(-3,'请求方法错误');
    }

    /**
     * 删除栏目
     * @param Category $category
     * @param Route $route
     * @return \think\response\Json
     */
    public function delete(Category $category,Route $route): \think\response\Json
    {
        if(request()->isPost()){
            $param = input('post.');
            try {
                validate(CategoryValidate::class)->scene('delete')->check($param);
            } catch (ValidateException $e) {
                return jsonReturn(-1, $e->getError());
            }
            $where = [
                'id' => $param['id'],
                'seller_id' => $this->admin['seller_id'],
                'website_id' => $param['website_id'],
                'lang' => $param['lang']
            ];
            Db::startTrans();
            try {
                $subCate = $category -> getAllCustomData(['seller_id'=>$this->admin['seller_id'],'parent_id'=>$param['id']])['data'];
                $this->deleteCateCacheKey($param['website_id'],$param['lang']);
                if(!empty($subCate)){
                    return jsonReturn(-1,'栏目下面有子栏目，不能直接删除');
                }
                $res = $category->delCategory($where);
                $route->delRoute(['seller_id' => $this->admin['seller_id'],'category_id'=>$param['id']]);
                $route->getRoutes($param['website_id'], $this->admin['seller_id'], $param['lang']);
                $optAdmin = request()->admin;
                event("AdminOptLog",[
                    'admin_id' => $optAdmin['uid'],
                    'admin_name' => $optAdmin['name'],
                    'title'=>"栏目管理",
                    "content"=>"删除栏目,栏目ID为".$param['id'],
                ]);
                Db::commit();
            }catch (ModelException $me){
                Db::rollback();
                return jsonReturn(50023,$me->getMessage());
            }catch (\Exception $e){
                Db::rollback();
                return jsonReturn(50024,$e->getMessage());
            }
            return json($res);
        }
        return jsonReturn(-3,'请求方法错误');
    }

    /**
     * @throws ModelException
     */
    public function getModuleCate(Category $Category): \think\response\Json
    {
        $param = input('get.');
        try {
            validate(CategoryValidate::class)->scene('getModuleCate')->check($param);
        } catch (ValidateException $e) {
            return jsonReturn(-1, $e->getError());
        }
        $siteIds = implode('_',$param['site_id']);
        $moduleCateKey = 'hc_module_cate_' . $this->admin['seller_id'] . '_' . $param['lang'] .'_' . $siteIds ;
        $tmpArr = [$moduleCateKey=>$moduleCateKey];
        $cacheKeyArr = $this->cacheKeyArr;
        $tmpKeyArr = Cache::get($cacheKeyArr);
        if(empty($tmpKeyArr)){
            $tmpKeyArr = $tmpArr;
        }else{
            $tmpKeyArr[$moduleCateKey] = $moduleCateKey;
        }
        Cache::set($cacheKeyArr,$tmpKeyArr);
        $siteIds = implode('_',$param['site_id']);
        $moduleCateKey = 'hc_module_cate_' . $this->admin['seller_id']. '_' . $param['lang'] .'_' . $siteIds ;
        $category = Cache::get($moduleCateKey);
        if(empty($category)){
            $website = new Website();
            $category = $website->getAllCustomData([['id','in',$param['site_id']],['seller_id','=',$this->admin['seller_id']],],'id asc','id,title,domain',['category'=>function($q){
                $q->order('sort asc');
            }])['data'];

            foreach($category as &$cate){
                $tmpCategory = $this->makeTree($cate['category']);
                $tmpCategory = $this->imp($tmpCategory);
                $cate['category'] = $tmpCategory;
            }
            Cache::set($moduleCateKey,$category);
        }
        return jsonReturn(0,'success',$category);
    }

    public function makeTree($data, int $pid=0, int $level=0): array
    {
        $tree = array();
        $tmpTree = [];
        foreach ($data as $key => &$value) {
            $str = str_repeat('--',$level);
            $value['title'] = $str . $value['title'];
            if ($value['parent_id'] == $pid) {
                $value['level'] = $level;
                unset($data[$key]);
                array_push($tmpTree,$value);
                $value['children'] = $this->makeTree($data, $value['id'],$level+1);
                $tree[] = $value;
            }else{
                array_push($tmpTree,$value);
            }
        }
        return $tree;
    }

    public function imp($tree, $children='children'): array
    {
        $impArr = array();
        foreach($tree as $w) {
            if(isset($w[$children])) {
                $t = $w[$children];
                unset($w[$children]);
                $impArr[] = $w;
                if(is_array($t)) $impArr = array_merge($impArr, $this->imp($t, $children));
            } else {
                $impArr[] = $w;
            }
        }
        return $impArr;
    }

    /**
     * 栏目复制
     * @throws ModelException
     * @throws \Exception
     */
    public function copy(CategoryService $categoryService): \think\response\Json
    {
        set_time_limit(300);
        $param = input('post.');
        try {
            validate(CategoryValidate::class)->scene('copy')->check($param);
        } catch (ValidateException $e) {
            return jsonReturn(-1, $e->getError());
        }
        foreach ($param['target_site'] as $val){
            if(empty($val) || !is_numeric($val)){
                return jsonReturn(-1,'目标站点数据异常，请检查');
            }
        }
        $res =  $categoryService -> copyCate($param['original_site'],$param['target_site'],$param['lang'],$this->admin['seller_id']);
        return json($res);
    }

    /**
     * @throws \app\exception\ModelEmptyException
     * @throws ModelException
     */
    public function getMapCateData(&$param)
    {
        $Category = new Category();
        $param['parent_path'] = json_encode($param['parent_map']);
        $param['parent_map'] = array_pop($param['parent_map']);
        $mapCate = $Category->getCategory(['id'=>$param['parent_map'],'seller_id'=>$this->admin['seller_id']])['data']->toArray();
        $param['alias'] = $mapCate['alias'];
        $param['list_tpl'] = $mapCate['list_tpl'];
        $param['detail_tpl'] = $mapCate['detail_tpl'];
        $param['module_id'] = $mapCate['module_id'];
        $param['type'] = $mapCate['type'];
        return $param;
    }

    public function deleteCateCacheKey($siteId,$lang)
    {
        $cateCacheKey = 'hc_cate_' . $this->admin['seller_id'] . '_' . $siteId .'_' . $lang;
        Cache::delete($cateCacheKey);
        $moduleCateArr = Cache::get($this->cacheKeyArr);
        if(!empty($moduleCateArr)){
            foreach ($moduleCateArr as $cate){
                $tmpCate = explode('_',str_replace('hc_module_cate_' . $this->admin['seller_id'] . '_' . $lang .'_','',$cate));
                if(in_array($siteId,$tmpCate)){
                    $moduleCateCacheKey = 'hc_module_cate_' . $this->admin['seller_id'] . '_' . $lang .'_' . $siteId;
                    Cache::delete($moduleCateCacheKey);
                    unset($moduleCateArr[$cate]);
                }
            }
            Cache::set($this->cacheKeyArr,$moduleCateArr);
        }
    }
}
